package net.zrnecko.bowlingnumbers.entity;

import java.util.StringTokenizer;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.validator.Pattern;


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;

/**
 *
 * @author zrnecko
 */
@Entity
@Name("pinGame")
@Scope(ScopeType.CONVERSATION)
@Table(name = "game")
public class PinGame extends FrameGame {

	private static final long serialVersionUID = 1L;
	@Logger
	private static Log log;

	@Pattern(regex = "(|((X|[0-9]{1,10};([0-9]{1,10}|/|-))\\|){9}" +
	"(X;X;X|" + "X;X;[0-9]{1,10}|" + "X;X;-|" + "X;[0-9]{1,10};([0-9]{1,10}|-|/)|" + "[0-9]{1,10};-)|" + "[0-9]{1,10};[0-9]{1,10}|" + "[0-9]{1,10};/;(X|[0-9]{1,10}))")
	private String pinDetails;

	@Transient
	private Frame[] frames = new Frame[10];

	@Override
	public void setFrameDetails(String frameDetails) {
		throw new UnsupportedOperationException("FrameDetails have to be set through setPinDetails!");

	}

	public String getPinDetails() {
		return pinDetails;
	}

	public void setPinDetails(String pinDetails) {
		this.pinDetails = pinDetails;
		parsePinDetail();
		computePinResult();
		//StringBuffer tmpFrameDetails = new StringBuffer();
		// parse pin details
		// set frameDetails
		//super.setFrameDetails(tmpFrameDetails.toString());

	}
	
	public void setFrames(Frame[] frames) {
		this.frames = frames;
	}

	public Frame[] getFrames() {
		return frames;
	}
	
	private void computePinResult() {
		// code to compute result can be deleted - result is computed
		// in computeFrameResult()
		StringBuffer tmpFrameDetails = new StringBuffer();
		int tmpResult = 0;
		Frame f = null;
		boolean buildingOnSpare = false;
		boolean buildingOnStrike = false;
		boolean buildingOn2Strikes = false;
		for (int i = 0; i < 9; i++) {
			f = getFrames()[i];
			if (!buildingOnSpare && !buildingOnStrike && !buildingOn2Strikes) {
				log.debug("Building on nothing");
				tmpResult += f.getStrikeShotPinFall() + f.getSpareShotPinFall();
			}
			if (buildingOnSpare) {
				log.debug("Building on spare");
				tmpResult += 2 * f.getStrikeShotPinFall() + f.getSpareShotPinFall();
			}
			if (buildingOnStrike) {
				log.debug("Building on strike");
				tmpResult += 2 * f.getStrikeShotPinFall() + 2 * f.getSpareShotPinFall();
			}
			if (buildingOn2Strikes) {
				log.debug("Building on 2 strikes");
				tmpResult += 3 * f.getStrikeShotPinFall() + 2 * f.getSpareShotPinFall();
			}
			log.debug("Result after frame " + (i + 1) + ": " + tmpResult);

			if (f.isStrike()) {
				if (buildingOnStrike || buildingOn2Strikes) {
					buildingOn2Strikes = true;
					buildingOnStrike = false;
				} else {
					buildingOnStrike = true;
				}
				buildingOnSpare = false;
			} else if (f.isSpare()) {
				buildingOnSpare = true;
				buildingOnStrike = false;
				buildingOn2Strikes = false;
			} else {
				buildingOnSpare = false;
				buildingOnStrike = false;
				buildingOn2Strikes = false;
			}
			if (f.isStrike()) {
				tmpFrameDetails.append("X|");
			} else {
				tmpFrameDetails.append("" + (f.getStrikeShotPinFall() == 0 ? "-" : f.getStrikeShotPinFall()));
				if (f.isSpare()) {
					tmpFrameDetails.append("/|");
				} else {
					tmpFrameDetails.append("" + (f.getSpareShotPinFall() == 0 ? "-" : f.getSpareShotPinFall()) + "|");
				}
			}

		}
		f = getFrames()[9];
		if (!buildingOnSpare && !buildingOnStrike && !buildingOn2Strikes) {
			tmpResult += f.getStrikeShotPinFall() + f.getSpareShotPinFall();
		}
		if (buildingOnSpare) {
			tmpResult += 2 * f.getStrikeShotPinFall() + f.getSpareShotPinFall();
		}
		if (buildingOnStrike) {
			tmpResult += 2 * f.getStrikeShotPinFall() + 2 * f.getSpareShotPinFall();
		}
		if (buildingOn2Strikes) {
			tmpResult += 3 * f.getStrikeShotPinFall() + 2 * f.getSpareShotPinFall();
		}
		if (f.getStrikeShotPinFall() == 10) {
			tmpFrameDetails.append("X");
			if (f.getSpareShotPinFall() == 10) {
				tmpFrameDetails.append("X");
				if (f.getThirdShotPinFall() == 10) {
					tmpFrameDetails.append("X");
				} else {
					tmpFrameDetails.append(f.getThirdShotPinFall() == 0 ? "-" : f.getThirdShotPinFall());
				}
			} else {
				tmpFrameDetails.append(f.getSpareShotPinFall() == 0 ? "-" : f.getSpareShotPinFall());
			}
		} else {
			tmpFrameDetails.append(f.getStrikeShotPinFall() == 0 ? "-" : f.getStrikeShotPinFall());
			if (f.getSpareShotPinFall() == 10 - f.getStrikeShotPinFall()) {
				tmpFrameDetails.append("/");
				tmpFrameDetails.append(f.getThirdShotPinFall() == 0 ? "-" : f.getThirdShotPinFall());
			} else {
				tmpFrameDetails.append(f.getSpareShotPinFall() == 0 ? "-" : f.getSpareShotPinFall());
			}

		}
		tmpResult += f.getThirdShotPinFall();
		log.debug("Result after frame 10: " + tmpResult);
		log.debug("Setting result to " + tmpResult);
		super.setFrameDetails(tmpFrameDetails.toString());
	

	}

	private void parsePinDetail() {
		StringTokenizer tokenizer = new StringTokenizer(pinDetails, "|");
		String frameString = null;
		Frame frame = null;
		for (int i = 0; i < 9; i++) {
			frameString = tokenizer.nextToken();
			log.debug("Frame number " + (i + 1) + " string: " + frameString);
			try {
				frame = new Frame(frameString, false, true);
			} catch (InvalidFrameTokenException e) {
				throw new InvalidGameLineException("Frame string " + frameString + " for frame " + (i + 1) + "invalid!");
			}
			log.debug(frame);

			frames[i] = frame;
		}
		frameString = tokenizer.nextToken();
		log.debug("Frame string: " + frameString);
		try {
			frame = new Frame(frameString, true, true);
		} catch (InvalidFrameTokenException e) {
			throw new InvalidGameLineException("Frame string " + frameString + " for frame 10 invalid!");
		}
		frames[9] = frame;

		//String gameResult = tokenizer.nextToken();
		//this.setResult(Integer.parseInt(gameResult));
		log.debug("Game parsed");
	}
}
